using System;
using System.Collections.Generic;
using System.Text;
using FlatRedBall;
using FlatRedBall.Input;
using FlatRedBall.AI.Pathfinding;
using FlatRedBall.Graphics.Animation;
using FlatRedBall.Graphics.Particle;
using Vector2 = Microsoft.Xna.Framework.Vector2;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Media;

using FlatRedBall.Graphics.Model;
using FlatRedBall.Math.Geometry;
using FlatRedBall.Math.Splines;

using Cursor = FlatRedBall.Gui.Cursor;
using GuiManager = FlatRedBall.Gui.GuiManager;
using FlatRedBall.Localization;

#if FRB_XNA || SILVERLIGHT
using Keys = Microsoft.Xna.Framework.Input.Keys;
using Vector3 = Microsoft.Xna.Framework.Vector3;
using Texture2D = Microsoft.Xna.Framework.Graphics.Texture2D;
#endif

namespace MP3.Screens
{
	public partial class GameScreen
	{
        float mGravity;     // this keeps track of the gravity of the ballz
        int powerUpCycle;   // this is the cycle to add a new powerup.
        Vector2[] mPositions; // this stores potential positions for powerups.
        int mCount;     // keeps track of the visible Pucks;
        int mScoreForTeam0 = 0; // keeps track of team1
        int mScoreForTeam1 = 0; // keeps track of team2
        const int MAX_PUCKS = 5;
        const int MAX_POW_CYCLES = 250;

        Texture2D DownwardGravity;  // Background for Dwongravity
        Texture2D UpwardGravity;    // Background for Upongravity
        Sprite Background;
        
        const float MIN_BOUNCE = 3f;       // Minimum bounce velocity to stop bouncing.
        const float DEFAULT_ELASTICITY = .8f; // Default elastic multiplier
        Random mR = new Random();

        Song backgroundmusic;

		void CustomInitialize()
		{
            mGravity = -0.3f;
            powerUpCycle = 0;
            AssignPlayerBallIndices();
            AssignPucks();
            AssignPowerUps();
            startMusic();
            initializeBackgrounds();
		}

		void CustomActivity(bool firstTimeCalled)
		{
            UpdatePlayerBallGravity();
            SpawnPowerUp();
            CollisionActivity();
            RemoveDeadPuck();
            UserControl();
            MoveBackground();
		}

		void CustomDestroy()
		{


		}

        static void CustomLoadStaticContent(string contentManagerName)
        {


        }

        private void initializeBackgrounds()
        {
            DownwardGravity = FlatRedBallServices.Load<Texture2D>("/Resources/Textures/GravityDown.png");
            UpwardGravity = FlatRedBallServices.Load<Texture2D>("/Resources/Textures/GravityUp.png");
            Background = new Sprite();
            Background = SpriteManager.AddSprite(DownwardGravity);
            
            
            Background.TextureAddressMode = Microsoft.Xna.Framework.Graphics.TextureAddressMode.Wrap;
            Background.RightTextureCoordinate = 5;
            Background.BottomTextureCoordinate = 6;
            Background.ScaleX = 25;
            Background.ScaleY = 40;
            Background.Z = -1;

        }

        // animation for backgrounds
        private void MoveBackground()
        {
            Background.Y += mGravity/10;
            Background.Y = Background.Y % 13.4f;
        }

        // Add the CollisionActivity method to your GameScreen.cs custom code file:
        private void CollisionActivity()
        {
            // Check player ball collisions against walls and goals.
            for (int i = 0; i < PlayerBallList.Count; i++)
            {
                if (PlayerBallList[i].Body.CollideAgainstBounce(CollisionFile, 0, 1, DEFAULT_ELASTICITY) ||
                PlayerBallList[i].Body.CollideAgainstBounce(Top2Walls, 0, 1, DEFAULT_ELASTICITY) ||
                PlayerBallList[i].Body.CollideAgainstBounce(GoalAreaFile, 0, 1, DEFAULT_ELASTICITY))
                    playSound("ballWallBounce");

                // check collision agianst powerups.
                // do this collision check only for visible powerups.
                for (int j = 0; j < PowerUpList.Count; j++)
                    if (PowerUpList[j].Visible && PlayerBallList[i].Body.CollideAgainst(PowerUpList[j].Body))
                            PowerUpLogic(j);


                // Check player ball collisions against each other.
                for (int j = i + 1; j < PlayerBallList.Count; j++)
                    if (PlayerBallList[i].Body.CollideAgainstBounce(PlayerBallList[j].Body, PlayerBallList[i].Mass, PlayerBallList[j].Mass, DEFAULT_ELASTICITY))
                        playSound("ballBallBounce");

                // Check player ball collisions against pucks.
                for (int j = 0; j < PuckList.Count; j++)
                    if(PuckList[j].Visible)
                        if (PlayerBallList[i].Body.CollideAgainstBounce(PuckList[j].Body, PlayerBallList[i].Mass, PuckList[j].Mass, DEFAULT_ELASTICITY))
                            playSound("ballBallBounce");

            }

            // Check puck collilsions.  Only need to check other pucks, walls and goals.
            for (int i = 0; i < PuckList.Count; i++)
            {
                // First, check to make sure the puck is visible before trying to
                // calculate collisions.
                if (PuckList[i].Visible)
                {
                    PuckList[i].CountMyDeath();

                    // If the puck hit the left goal, give team 0 a point.
                    if (PuckList[i].Body.CollideAgainst(LeftGoal))
                          AssignGoalToTeam(0 , i);
                        
                    // If the puck hit the right goal, give team 1 a point.
                    else if (PuckList[i].Body.CollideAgainst(RightGoal))
                        AssignGoalToTeam(1, i);

                    // Check for a minimum bounce velocity.
                    if (PuckList[i].Velocity.Length() < MIN_BOUNCE)
                        // If below the threshold, bounce with 0 elasticity to stop the bouncing.
                        PuckList[i].Body.CollideAgainstBounce(CollisionFile, 0, 1, 0);

                    else
                        if (PuckList[i].Body.CollideAgainstBounce(CollisionFile, 0, 1, DEFAULT_ELASTICITY))
                            playSound("ballWallBounce");

                    // If the puck hit any of the top 2  walls, bounce it off.
                    PuckList[i].Body.CollideAgainstBounce(Top2Walls, 0, 1, 0);


                    // Check remaining pucks for collisions, starting at the current
                    // puck and working forward through Pucklist.  This ensures that
                    // collisions will not be calculated twice.
                    for (int j = i+1; j < PuckList.Count; j++)
                    {
                        if (PuckList[j].Visible)
                            if(PuckList[i].Body.CollideAgainstBounce(PuckList[j].Body, PuckList[i].Mass, PuckList[j].Mass, 0.7f))
                                playSound("ballBallBounce");
                    }
                }

            }
        }

        // Give a team a goal.
        private void AssignGoalToTeam(int teamIndex, int target)
        {
            playSound("goal");
            switch (teamIndex)
            {
                case 0:
                    mScoreForTeam0++;
                    ScoreHUDInstance.Score1 = mScoreForTeam0;
                    break;
                case 1:
                    mScoreForTeam1++;
                    ScoreHUDInstance.Score2 = mScoreForTeam1;
                    break;
                default:
                    throw new ArgumentException("Team index must be either 0 or 1");
            }

          
            // Once a goal has been made, hide the puck that made it
            // and add a new one if there aren't any left.
            HidePuck(target);

            if (mCount < 1)
                AddPuck();
            
        }

        private void RemoveDeadPuck()
        {
            for (int i = 0; i < PuckList.Count; i++)
            {
                if (PuckList[i].deathCount < 0)
                    HidePuck(i);        

                if (mCount < 1)
                    AddPuck();
            }
        }

        // Remove a puck from the game.
        private void HidePuck(int i)
        {
            if (i < 0 && i > 5)
                return;
            PuckList[i].Visible = false;
            PuckList[i].Gravity = 0;
            PuckList[i].deathCount = 200;
            PuckList[i].Velocity = Vector3.Zero;
            PuckList[i].Acceleration = Vector3.Zero;
            mCount--;


        }

        // Add a new puck to the game.
        private void AddPuck()
        {
            for (int i = 0; i < PuckList.Count; i++)
            {
                if (!PuckList[i].Visible)
                {
                    ShowPuck(i);
                    mCount++;
                    break;
                }
            }
        }

        // Set up pucks.
        private void AssignPucks()
        {
            foreach (Entities.Puck p in PuckList)
            {
                p.Visible = false;
                p.Gravity = 0;
                p.Velocity = Vector3.Zero;
                p.Acceleration = Vector3.Zero;
                p.deathCount = 200;
            }
            ShowPuck(0);
            mCount = 1;
        }

        // Show a new puck.
        private void ShowPuck(int i)
        {
            PuckList[i].Y = 12f;
            PuckList[i].X = mR.Next(4) - 2;
            PuckList[i].Visible = true;
            PuckList[i].Gravity = mGravity;
            PuckList[i].Velocity = Vector3.Zero;
            PuckList[i].deathCount = 200;
            PuckList[i].BodyRadius = 4f / (float)mR.Next(3, 8);
            PuckList[i].Mass = ((float) Math.PI) * PuckList[i].BodyRadius * PuckList[i].BodyRadius;
            
            PuckList[i].Tex.ScaleX = PuckList[i].Tex.ScaleY = PuckList[i].BodyRadius;
        }

        // assign player indexes for team.
        private void AssignPlayerBallIndices()
        {
            for (int i = 0; i < PlayerBallList.Count; i++)
            {
                PlayerBallList[i].PlayerIndex = i;
            }

            PlayerBallList[0].Tex.Texture = FlatRedBallServices.Load<Texture2D>("/Resources/Textures/BlueBumper.png");
            PlayerBallList[1].Tex.Texture = FlatRedBallServices.Load<Texture2D>("/Resources/Textures/RedBumper.png");
            

        }

        // assign the powerups
        private void AssignPowerUps()
        {
            ResetPowerUp();
            mPositions = new Vector2[4];
            mPositions[0] = new Vector2(-11, 11);
            mPositions[1] = new Vector2(-11, -11);
            mPositions[2] = new Vector2(11, 11);
            mPositions[3] = new Vector2(11, -11);
           
        }

        // add new powerup
        private void AddPowerUp()
        {            
            int index = 0;
            if (mCount == MAX_PUCKS)
                index = 1;
            else if (mR.Next(0, 3) > 1)
                index = 1;
            Vector2 pos = GetPosition();
            PowerUpList[index].X = pos.X;
            PowerUpList[index].Y = pos.Y;
            PowerUpList[index].Visible = true;
        }

        // returns a random position for the powerups
        private Vector2 GetPosition()
        {
            Vector2 returnVal = mPositions[mR.Next(0, mPositions.Length)];
            return returnVal;
        }

        // spawns a random powerup
        private void SpawnPowerUp()
        {
            if (powerUpCycle == MAX_POW_CYCLES)
            {
                ResetPowerUp();
                AddPowerUp();
            }
            powerUpCycle++;
        }


        // reset all the powerups
        private void ResetPowerUp()
        {
            for (int i = 0; i < PowerUpList.Count; i++)
            {
                PowerUpList[i].Visible = false;
            }
            powerUpCycle = 0;
            PowerUpList[0].Tex.Texture = FlatRedBallServices.Load<Texture2D>("/Resources/Textures/powerup_addball.png");
            PowerUpList[1].Tex.Texture = FlatRedBallServices.Load<Texture2D>("/Resources/Textures/powerup_gravityswap.png");
            PowerUpList[1].Tex.ScaleX =
                PowerUpList[1].Tex.ScaleY =
                PowerUpList[0].Tex.ScaleX =
                PowerUpList[0].Tex.ScaleY =
                PowerUpList[0].BodyRadius;
        }


        // implements powerup effect.
        private void PowerUpLogic(int power)
        {
            if (power == 0)
                AddPuck();
           
            else if (power == 1)
            {
                mGravity *= -1;

                if (mGravity < 0)
                    SpriteManager.ReplaceTexture(UpwardGravity, DownwardGravity);
                else
                    SpriteManager.ReplaceTexture(DownwardGravity, UpwardGravity);

                for (int i = 0; i < PuckList.Count; i++)
                {
                    if (PuckList[i].Visible)
                        PuckList[i].Gravity = mGravity;
                }
            }
            ResetPowerUp();
        }

        // starts the background music
        private void startMusic()
        {
            backgroundmusic = FlatRedBallServices.Load<Song>(@"Content\\Audio\\background");
            MediaPlayer.Volume = .2f;
            MediaPlayer.IsRepeating = true;
            MediaPlayer.Play(backgroundmusic);
        }

        // plays a sound effect
        private void playSound(string se)
        {
            SoundEffect sound = FlatRedBallServices.Load<SoundEffect>(@"Content\\Audio\\" + se);
            sound.Play();
        }

        // Add  puck when player press X
        private void UserControl()
        {
            for (int i = 0; i < PlayerBallList.Count; i++)
            {
                if (PlayerBallList[i].mGamePad.ButtonPushed(Xbox360GamePad.Button.X))
                    AddPuck();
            }
        }

        
        private void UpdatePlayerBallGravity()
        {
            for (int i = 0; i < PlayerBallList.Count; i++)
            {
                if (PlayerBallList[i].CurrentState == Entities.PlayerBall.VariableState.Moving)
                {
                    PlayerBallList[i].Gravity = mGravity * 2;
                }
            }
        }        
	}
}
